package com.clj.blesample;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

import com.arashivision.ble.BleInfoUpdateListener;
import com.arashivision.ble.OneBle;
import com.arashivision.ble.OneBleCallbacks;
import com.arashivision.onecamera.OneDriverInfo;
import com.arashivision.onecamera.cameranotification.BatteryStatus;
import com.arashivision.onecamera.cameranotification.NotificationCaptureAutoSplit;
import com.arashivision.onecamera.cameranotification.NotificationCaptureStopped;
import com.arashivision.onecamera.cameranotification.NotificationCardUpdate;
import com.arashivision.onecamera.cameranotification.NotificationShutdown;
import com.arashivision.onecamera.cameranotification.NotificationTakePictureStateUpdate;
import com.arashivision.onecamera.cameranotification.NotificatoinConnectedToPeripheral;
import com.arashivision.onecamera.cameranotification.NotificatoinDisconnectedPeripheral;
import com.arashivision.onecamera.cameranotification.NotificatoinKeyPressed;
import com.arashivision.onecamera.cameraresponse.CalibrateGyroResp;
import com.arashivision.onecamera.cameraresponse.CameraCaptureStatus;
import com.arashivision.onecamera.cameraresponse.DeleteFilesResp;
import com.arashivision.onecamera.cameraresponse.EraseSdcardResp;
import com.arashivision.onecamera.cameraresponse.GetCurrentCaptureStatusResp;
import com.arashivision.onecamera.cameraresponse.GetFileExtraResp;
import com.arashivision.onecamera.cameraresponse.GetFileListResp;
import com.arashivision.onecamera.cameraresponse.GetMiniThumbResp;
import com.arashivision.onecamera.cameraresponse.GetOptionsResp;
import com.arashivision.onecamera.cameraresponse.GetPhotographyOptionsResp;
import com.arashivision.onecamera.cameraresponse.GetTimelapseOptionsResp;
import com.arashivision.onecamera.cameraresponse.SetOptionsResp;
import com.arashivision.onecamera.cameraresponse.SetPhotographyOptionsResp;
import com.arashivision.onecamera.cameraresponse.SetTimelapseOptionsResp;
import com.arashivision.onecamera.cameraresponse.TakePictureResponse;
import com.arashivision.onecamera.cameraresponse.TestSDCardSpeedResp;
import com.arashivision.onecamera.cameraresponse.VideoResult;
import com.clj.fastble.data.ScanResult;
import com.clj.fastble.utils.BleLog;

import org.greenrobot.eventbus.EventBus;

import static com.arashivision.onecamera.OneDriverInfo.Response.InfoType.GET_CURRENT_CAPTURE_STATUS;

/**
 * Created by vans on 29/11/17.
 */

public class BleService extends OneBle
{
    private static final String TAG = "BleService";
    private static BleService mInstance;
    private static final Object mSyncObject = new Object();

    private static class OneBleServiceCallback implements OneBleCallbacks
    {
        @Override
        public void onRecordVideoStateNotify(int state, VideoResult mResult)
        {
            EventBus.getDefault().post(new RecordCompleteWithStorageEvent(state, mResult));
        }

        @Override
        public void onStillImageWithStorageNotify(TakePictureResponse mResponse)
        {
            EventBus.getDefault().post(new TakePictureWithStorageEvent(mResponse));
        }

        @Override
        public void onTimelapseNotify(int state, VideoResult mResult)
        {
            EventBus.getDefault().post(new TimelapseNotifyEvent(state,mResult));
        }

        @Override
        public void onServicesDiscoveredFail()
        {
            EventBus.getDefault().post(new ServicesDiscoveredFailEvent());
        }

        @Override
        public void onStartScan() {
            EventBus.getDefault().post(new StartScanEvent());
        }

        @Override
        public void onScanning(ScanResult result) {
            EventBus.getDefault().post(new ScanningEvent(result));
        }

        @Override
        public void onScanComplete() {
            EventBus.getDefault().post(new ScanCompleteEvent());
        }

        @Override
        public void onConnecting() {
            EventBus.getDefault().post(new ConnectingEvent());
        }

        @Override
        public void onConnectFail() {
            EventBus.getDefault().post(new ConnectFailEvent());
        }

        @Override
        public void onDisConnected() {
            EventBus.getDefault().post(new DisConnectedEvent());
        }

        @Override
        public void onServicesDiscovered()
        {
            EventBus.getDefault().post(new ServicesDiscoveredEvent(new CameraCaptureStatus()));
        }

        @Override
        public void onBleErrorState(int state)
        {
            Log.e(TAG,"onBleErrorState state " + state);
            EventBus.getDefault().post(new BleErrorEvent(state));
        }

        @Override
        public void onScanFail()
        {
            Log.i(TAG," onScanFail  " );
            EventBus.getDefault().post(new ScanFailEvent());
        }

        @Override
        public void onReadRssi(int rssi)
        {
            Log.i(TAG,"onReadRssi  " + rssi);
            EventBus.getDefault().post(new ReadRssiEvent(rssi));
        }

        @Override
        public void onStartWakeUpSuccess()
        {
            EventBus.getDefault().post(new StartBCSuccessEvent());
        }

        @Override
        public void onStartWakeUpFail(int errorCode)
        {
            EventBus.getDefault().post(new StartBCFailEvent(errorCode));
        }

        @Override
        public void onStopWakeUpSuccess()
        {
            EventBus.getDefault().post(new StopBCSuccessEvent());
        }

        @Override
        public void onStopWakeUpFail(int errorCode)
        {
            EventBus.getDefault().post(new StopBCFailEvent(errorCode));
        }
    }

    public static BleService instance(Context context)
    {
        synchronized (mSyncObject)
        {
            if (mInstance != null)
                return mInstance;
            Context appContext = context.getApplicationContext();
            // Pass a null callback handler to OneCamera we let it execute callbacks on its thread.
            // Here we just post event to the receiver in those callback, so it doesn't matter
            Handler callbackHandler = null;
            OneBleServiceCallback mCallBacks = new OneBleServiceCallback();
            mInstance = new BleService(appContext, mCallBacks, callbackHandler);

            return mInstance;
        }
    }


    private BleService(Context context, OneBleCallbacks callbacks, Handler handler)
    {
        super(context, callbacks, handler);
        setInfoUpdateListener(null, new BleInfoUpdateListener()
        {
            @Override
            public void onCameraInfoNotify(int what, int error, Object obj)
            {
                Log.i(TAG, "what " + what + " error " + error);
                //open if need debug 171113
                switch (what)
                {
                    case OneDriverInfo.Response.InfoType.FIRMWARE_UPGRADE_COMPLETE:
                        break;
                    case OneDriverInfo.Response.InfoType.RECORD_AUTO_SPLIT:
                    {
                        NotificationCaptureAutoSplit notify = (NotificationCaptureAutoSplit) obj;
                        Log.i(TAG, "uri " + notify.mVideo.uri);
                        Log.i(TAG, "file_size " + notify.mVideo.file_size);
                        Log.i(TAG, "total_time " + notify.mVideo.total_time);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.BATTERY_UPDATE:
                    {
                        BatteryStatus notify = (BatteryStatus) obj;
                        Log.i(TAG, "power_type " + notify.power_type);
                        Log.i(TAG, "battery_scale " + notify.battery_scale);
                        Log.i(TAG, "battery_level " + notify.battery_level);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.BATTERY_LOW:
                    {
                        BatteryStatus notify = (BatteryStatus) obj;
                        Log.i(TAG, "power_type " + notify.power_type);
                        Log.i(TAG, "battery_scale " + notify.battery_scale);
                        Log.i(TAG, "battery_level " + notify.battery_level);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.SHUTDOWN:
                    {
                        NotificationShutdown notify = (NotificationShutdown) obj;
                        Log.i(TAG, "err_code " + notify.err_code);
                        Log.i(TAG, "message " + notify.message);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.STORAGE_UPDATE:
                    {
                        NotificationCardUpdate notify = (NotificationCardUpdate) obj;
                        Log.i(TAG, "card_state " + notify.card_state);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.STORAGE_FULL:
                    {
                        Log.i(TAG, "storage full");
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.BUTTON_PRESSED:
                    {
                        NotificatoinKeyPressed notify = (NotificatoinKeyPressed) obj;
                        Log.i(TAG, "key_id " + notify.key_id);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.RECORD_STOPPED:
                    {
                        NotificationCaptureStopped notify = (NotificationCaptureStopped) obj;
                        if(notify != null)
                        {
                            Log.i(TAG, "err_code " + notify.err_code);
                            Log.i(TAG, "uri " + notify.mVideo.uri);
                            Log.i(TAG, "file_size " + notify.mVideo.file_size);
                            Log.i(TAG, "total_time " + notify.mVideo.total_time);
                        }
                        else
                        {
                            BleLog.i(" RECORD_STOPPED notify null");
                        }
                        break;
                    }
                    case OneDriverInfo.Response.InfoType.CAPTURE_STILL_IMAGE_STATE_UPDATE:
                    {
                        NotificationTakePictureStateUpdate notify = (NotificationTakePictureStateUpdate) obj;
                        Log.i(TAG, "state " + notify.state);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.DELETE_FILES:
                    {
                        DeleteFilesResp notify = (DeleteFilesResp) obj;
                        Log.i(TAG, "delete notify id " + notify.requestID);
                    }
                    break;
                    //deprecated
                    case OneDriverInfo.Response.InfoType.PHONE_INSERT:
                    {
                        Log.i(TAG, "PhotoInsert");
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.BT_DISCOVER_PERIPHERAL:
                    {
                        NotificatoinDisconnectedPeripheral notify = (NotificatoinDisconnectedPeripheral) obj;
                        break;
                    }
                    case OneDriverInfo.Response.InfoType.BT_CONNECTED_TO_PERIPHERAL:
                    {
                        NotificatoinConnectedToPeripheral notify = (NotificatoinConnectedToPeripheral) obj;
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.BT_DISCONNECTED_PERIPHERAL:
                    {
                        NotificatoinDisconnectedPeripheral notify = (NotificatoinDisconnectedPeripheral) obj;
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.STOP_LIVE_STREAM:
                    case OneDriverInfo.Response.InfoType.CANCEL_CAPTURE:
                        break;
                    //async response
                    case OneDriverInfo.Response.InfoType.GET_FILE_EXTRA:
                    {
                        GetFileExtraResp notify = (GetFileExtraResp) obj;
                        Log.i(TAG, "GetFileExtraResp extra len " + notify.extraData.length);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.GET_FILE_LIST:
                    {
                        GetFileListResp notify = (GetFileListResp) obj;
                        Log.i(TAG, "GetFileListResp  len " + notify.mUriList.size());
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.GET_FILEINFO_LIST:
                        break;
                    case OneDriverInfo.Response.InfoType.SET_FILE_EXTRA:
                    {
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.ERASE_SD_CARD:
                    {
                        EraseSdcardResp notify = (EraseSdcardResp) obj;
                        if(notify != null)
                        {
                            Log.i(TAG, "erase notify id " + notify.requestID);
                        }
                        else
                        {
                            Log.i(TAG, "EraseSdcardResp null ");
                        }
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.CALIBRATE_GYRO:
                    {
                        CalibrateGyroResp mResp = (CalibrateGyroResp)obj;
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.GET_MINI_THUMBNAIL:
                    {
                        GetMiniThumbResp notify = (GetMiniThumbResp) obj;
                        Log.i(TAG, "GET_MINI_THUMBNAIL thumb len " + notify.thumb.length);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.TEST_SD_CARD_SPEED:
                    {
                        TestSDCardSpeedResp notify = (TestSDCardSpeedResp) obj;
                        Log.i(TAG, "TEST_SD_CARD_SPEED thumb len " + notify.write_speeds.length);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.SET_OPTIONS:
                    {
                        SetOptionsResp notify = (SetOptionsResp) obj;
                        Log.i(TAG, "SetOptionsResp id " + notify.requestID);
                    }
                        break;
                    case OneDriverInfo.Response.InfoType.GET_OPTIONS:
                    {
                        GetOptionsResp notify = (GetOptionsResp) obj;
                        Log.i(TAG, "GetOptionsResp id " + notify.requestID);
                    }
                        break;
                    case OneDriverInfo.Response.InfoType.SET_PHOTOGRAPHY_OPTIONS:
                    {
                        SetPhotographyOptionsResp notify = (SetPhotographyOptionsResp) obj;
                        Log.i(TAG, "SetPhotographyOptionsResp id " + notify.requestID);
                    }
                        break;
                    case OneDriverInfo.Response.InfoType.GET_PHOTOGRAPHY_OPTIONS:
                    {
                        GetPhotographyOptionsResp notify = (GetPhotographyOptionsResp) obj;
                        Log.i(TAG, "GetPhotographyOptionsResp id " + notify.requestID);
                    }
                        break;
                    case OneDriverInfo.Response.InfoType.GET_TIMELAPSE_OPTIONS:
                    {
                        GetTimelapseOptionsResp notify = (GetTimelapseOptionsResp) obj;
                        Log.i(TAG, "GetTimelapseOptionsResp id " + notify.requestID +
                                "　durationS　" + notify.timelapse_options.durationS +
                                    " lapseTimeMs " + notify.timelapse_options.lapseTimeMs);
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.SET_TIMELAPSE_OPTIONS:
                    {
                        SetTimelapseOptionsResp notify = (SetTimelapseOptionsResp) obj;
                        Log.i(TAG, "SetTimelapseOptionsResp id " + notify.requestID + " result " + notify.result );
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.REBOOT_CAMERA:
                    {
                        Log.i(TAG, "reboot resp");
                    }
                    break;
                    case GET_CURRENT_CAPTURE_STATUS:
                    {
                        GetCurrentCaptureStatusResp notify = (GetCurrentCaptureStatusResp)obj;
                        Log.d(TAG,"GetCurrentCaptureStatusResp id " + notify.requestID
                                + " notify res " + notify.errorCode
                                + " status " + notify.status.state + " time " + notify.status.capture_time );
                    }
                    break;
                    case OneDriverInfo.Response.InfoType.CAMERA_STATUS_NOTIFY:
                    {
                        CameraCaptureStatus notify = (CameraCaptureStatus) obj;
                        Log.i(TAG, "CameraCaptureStatus");
                    }
                    break;
                    default:
                        break;
                }
                if(mInfoNotify != null)
                {
                    mInfoNotify.infoNotify(what, error,obj);
                }
            }
        });
    }

    private InfoNotify mInfoNotify;
    public void setInfoNotify(InfoNotify notify)
    {
        mInfoNotify = notify;
    }

    public interface InfoNotify
    {
        void infoNotify(int what,int error,Object obj);
    }

    public static class RecordCompleteWithStorageEvent
    {
        public RecordCompleteWithStorageEvent(int state, VideoResult mResult)
        {
            this.mResult = mResult;
            this.state = state;
        }

        public VideoResult mResult;
        public int state;
    }

    public static class TakePictureWithStorageEvent
    {
        public TakePictureWithStorageEvent(TakePictureResponse mResponse)
        {
            this.mResult = mResponse;
        }
        public TakePictureResponse mResult;
    }

    public static class TimelapseNotifyEvent
    {
        public int state;
        public VideoResult mResult;
        public TimelapseNotifyEvent(int state, VideoResult mResult)
        {
            this.state = state;
            this.mResult = mResult;
        }
    }

    public static class ServicesDiscoveredEvent
    {
        CameraCaptureStatus mCaptureStatus;
        public ServicesDiscoveredEvent(CameraCaptureStatus mStatus)
        {
            this.mCaptureStatus = mStatus;
        }
    }

    public static class BleErrorEvent
    {
        public int error;
        public BleErrorEvent(int error)
        {
            this.error = error;
        }
    }

    public static class ScanFailEvent
    {
        public ScanFailEvent()
        {
        }
    }

    public static class ReadRssiEvent
    {
        int rssi;
        public ReadRssiEvent(int rssi)
        {
            this.rssi = rssi;
        }
    }

    public static class ServicesDiscoveredFailEvent
    {
        public ServicesDiscoveredFailEvent()
        {
        }
    }

    public static class StartBCSuccessEvent
    {
        public StartBCSuccessEvent()
        {
        }
    }

    public static class StartBCFailEvent
    {
        int errorCode;
        public StartBCFailEvent(int rssi)
        {
            this.errorCode = rssi;
        }
    }

    public static class StopBCSuccessEvent
    {
        public StopBCSuccessEvent()
        {
        }
    }

    public static class StopBCFailEvent
    {
        int errorCode;
        public StopBCFailEvent(int rssi)
        {
            this.errorCode = rssi;
        }
    }

    public static class StartScanEvent
    {
        public StartScanEvent()
        {
        }

    }

    public static class ScanningEvent
    {
        public ScanningEvent(ScanResult result)
        {
            this.result = result;
        }

        public ScanResult result;
    }

    public static class ScanCompleteEvent
    {
        public ScanCompleteEvent()
        {

        }
    }

    public static class ConnectingEvent
    {
        public ConnectingEvent()
        {

        }

    }

    public static class DisConnectedEvent
    {
        public DisConnectedEvent()
        {

        }
    }

    public static class ConnectFailEvent
    {
        public ConnectFailEvent()
        {

        }
    }
}
